package REMC.objects;

import java.util.Iterator;
import java.util.Vector;

import main.Grid;

/**
 * @authors Tal Cohen & Adiel Ashrov
 * this class represent the c vector in the replica exchange algorithm
 */
public class CVector extends Vector<Replica> {

	/**
	 * initializing the vector of replicas
	 * @param replica the base replica to create the vector from.
	 * @param size number of replicas in vector.
	 */
	public CVector(Replica replica, int size){
		Replica tempRep;
		Grid grid;
		boolean bruteMode = true; // hard coded - set true if you want to set temperatures 
								  // according to values in method "calcTempBruteForce" 
		for(int i=0; i<size; i++){
			grid = new Grid(replica.sequence.length(), replica.dimensions);
			
			if(!bruteMode)
			{
				tempRep = new Replica(replica.dimensions, replica.sequence, 
					replica.random, grid, "replica_"+i,calcTempByProb(i,size));
			}
			else
			{
				tempRep = new Replica(replica.dimensions, replica.sequence, 
						replica.random, grid, "replica_"+i,calcTempBruteForce(i));
			}
			add(tempRep);
		}
	}
	
	/**
	 * returns temerture that assures propability of (i+1)/size to accept replica with
	 * higher energies in monte carlo search 
	 * @param i - the index of the replica in the vec
	 * @param size - the vector size.
	 * @return the temperature that matches the replica i in the vec.
	 */
	private Double calcTempByProb(int i, int size) {
		Double temperature = 0.0,tProbability;
		if (i!= size-1){
			Double tInterval = (1.0 / size);
			tProbability = tInterval + i*(tInterval);
			temperature = (-1 / (Math.log(tProbability)));
		}else{
			tProbability = 0.99;
			temperature = 100.0;
		}
		System.out.println("tProbability="+tProbability+",temperature="+temperature);
		return temperature;
	}
	
	/**
	 * hard coded temperatures for the vector
	 * @param i
	 * @return
	 */
	private Double calcTempBruteForce(int i) {
		Double temperature = 0.0;
		switch(i){
		case 0 :	temperature =  0.29070424077888807;
					break;
		case 1 :	temperature =  0.4365426671749166;
					break;
		case 2 :	temperature = 0.6492127684000335;
					break;
		case 3 :	temperature = 1.682203951234278;
					break;
		case 4 :	temperature = 100.0;//use 5 replicas
					break;
		case 5 :	temperature = 7.592977264823924;
					break;
		case 6 :	temperature = 100.0;
					break;
		case 7 :	temperature = 3.80920710006587;
					break;
		case 8 :	temperature = 7.59297726482392;
					break;
		case 9 :	temperature = 100.0;
					break;
		default : 	temperature = 0.0;
					break;
		}
		//MyLogger.getLogger().Log("temperature "+ i + " = " +temperature);
		return temperature;
	}
	
	/**
	 * swapping lables(position in vector) between replica i to replica j 
	 * temperature is also swapped in order to save the temperature in the vector's position
	 * @param i
	 * @param j
	 */
	public void swapLables(int i, int j){
		if (i < this.size() && j < this.size() && Math.abs(j-i)==1){
			//first we swap the temperatures
			Double tempI = this.get(i).get_temperature();
			Double tempJ = this.get(j).get_temperature();
			this.get(j).set_temperature(tempI);
			this.get(i).set_temperature(tempJ);

			//swap the replicas
			Replica tRep = this.get(i);
			this.set(i,this.get(j));
			this.set(j,tRep);
		}		
	}
	
	//for printing the vector...
	@Override
	public String toString(){
		String ans = "********* start of CVector *********\n";
		
		for (Iterator<Replica> iterator = this.iterator(); iterator.hasNext();) {
			Replica replica = iterator.next();
			ans+= replica.toString();
		}	
		return ans + "********* end of CVector *********\n";
	}
	
	//for printing the vector...short version
	public String toStringShort(){
		String ans = "********* start of CVector *********\n";
		
		for (Iterator<Replica> iterator = this.iterator(); iterator.hasNext();) {
			Replica replica = iterator.next();
			ans+= replica.toStringForCVec();
		}	
		return ans + "********* end of CVector *********\n";
	}
}
